package com.example.ipccore;

import com.example.ipccore.request.RequestBean;

import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;

public class CacheCenter {
    private static final CacheCenter ourInstance = new CacheCenter();
    public static CacheCenter getInstance(){
        return ourInstance;
    }

    //类表
    private final ConcurrentHashMap<String,Class<?>> mClassMap;
    //方法表
    private final ConcurrentHashMap<String, ConcurrentHashMap<String, Method>> mAllMethodMap;
    //实例对象表
    private final ConcurrentHashMap<String,Object> mInstanceObjectMap;

    public CacheCenter() {
        mClassMap = new ConcurrentHashMap<>();
        mInstanceObjectMap = new ConcurrentHashMap<>();
        mAllMethodMap = new ConcurrentHashMap<>();
    }

    public void register(String key, Class<?> clazz) {
        //第一步，先将class注册到类表中去。
        registerClass(key,clazz);
        //第二步，注册方法
        registerMethod(key,clazz);
        //第三张表需要在  服务注册时将服务对象初始化吗？
        // 答：不能，只有当发生服务调用时才进行初始化。否则有些服务一辈子不会被调用导致性能浪费。
        //所以在服务注册时，不初始化服务实例对象。而是在服务调用时进行服务的实例化。
    }

    private void registerMethod(String key, Class<?> clazz) {
        //遍历类中方法进行记录
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            ConcurrentHashMap<String, Method> map = mAllMethodMap.get(clazz.getName());
            //首次没有map则新建
            if (map==null) {
                map=new ConcurrentHashMap<>();
                mAllMethodMap.put(clazz.getName(),map);
            }
            //key：能不能直接用方法名作为Key？不能，存在重载函数。
            // 所以key需要做方法签名
            String methodParameters = getMethodParameters(method);
            map.put(methodParameters,method);
        }
    }

    public static String getMethodParameters(RequestBean requestBean) {
        StringBuilder result = new StringBuilder();
        result.append(requestBean.getMethodName());
        if (requestBean.getRequestParameters()==null || requestBean.getRequestParameters().length==0){
            return result.toString();
        }

        int length=requestBean.getRequestParameters().length;
        if (length==0){
            return result.toString();
        }
        for (int i = 0; i < length; i++) {
            result.append("_").append(requestBean.getRequestParameters()[i].getParameterClassName());
        }
        return result.toString();
    }

    //无参则是method.getName值，有参则是 method.getName+"_"+参数类型。
    //类似于JNI的函数签名
    private String getMethodParameters(Method method) {
        StringBuilder result = new StringBuilder();
        result.append(method.getName());
        Class<?>[] classes = method.getParameterTypes();
        int length=classes.length;
        if (length==0){
            return result.toString();
        }
        for (int i = 0; i < length; i++) {
            result.append("_").append(classes[i].getName());
        }
        return result.toString();
    }

    //将Class存到类表中
    private void registerClass(String key, Class<?> clazz) {
        mClassMap.put(key, clazz);
    }

    public Class<?> getClassType(String parameterClassName) {
        try {
            Class<?> aClass = Class.forName(parameterClassName);
            return aClass;
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }finally {
            return null;
        }
    }

    public Method getMethod(RequestBean requestBean) {
        ConcurrentHashMap<String, Method> map = mAllMethodMap.get(requestBean.getClassName());
        if (map!=null){
            String key = getMethodParameters(requestBean);
            return map.get(key);
        }
        return null;
    }

    /**
     *
     * @param className
     * @param instance
     */
    public void putObject(String className, Object instance) {
        mInstanceObjectMap.put(className, instance);
    }

    public Object getObject(String className) {
        return mInstanceObjectMap.get(className);
    }
}
